home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / presto / presto10.lha / src / presto.C < prev    next >
C/C++ Source or Header  |  1991-12-11  |  7KB  |  284 lines

  1. /*
  2.  * presto.c
  3.  *
  4.  *    Main PRESTO bootstrapping code.  Works something like this:
  5.  *
  6.  *    main()
  7.  *        Create a new MAIN object.
  8.  *        delete the scheduler thread
  9.  *        exit
  10.  *
  11.  *    Main::Main()
  12.  *        Call Main::init giving programmer chance to set up
  13.  *        initial parameters.
  14.  *
  15.  *    -    Bind "thisthread" to the default thread we get from UNIX.
  16.  *    -    Create a new scheduler object.
  17.  *    -    Create a thread to run in the scheduler object.
  18.  *    -    Start new thread in scheduler object.  We are running 
  19.  *        without preemption and with a single processor at this
  20.  *        point, so the start just puts the thread/scheduler pair
  21.  *        on the ready queue.
  22.  *    -    Create nummainthreads bound to Main::main and "start" them
  23.  *        by placing them on the run queue.  Again, we know that 
  24.  *        they won't run until the scheduler actually kicks in.
  25.  *
  26.  *    -    Invoke "thisproc" getting it to start pulling threads
  27.  *        off the readyq.
  28.  */
  29.  
  30. #define _PRESTO_C
  31.  
  32.  
  33. #include <stddef.h>
  34. #include <sys/types.h>
  35. #include <osfcn.h>
  36. #include <stream.h>
  37. #include "presto.h"
  38.  
  39. Main            *MAIN;
  40. Scheduler    *sched;            // does not need to be shared,
  41.                     // just what it references does
  42.  
  43. static int main_exit_code = 0;        // how we leave
  44. shared_t int prestoState = STATIC_CTOR;
  45.  
  46. start_Scheduler (Scheduler *s)
  47.  
  48. {
  49.   return s->invoke();
  50. }
  51.  
  52. start_Main (Main *m)
  53.  
  54. {
  55.   return m->main ();
  56. }
  57.  
  58. Main::Main(int ac, char **ap, char **ep)
  59. {
  60.     argc = ac;
  61.     argv = ap;
  62.     envp = ep;
  63.     numprocessors = 1;
  64.     mainstacksizes = DEFSTACKSIZ;
  65.     nummainthreads = 1;
  66.     stacksize = DEFSTACKSIZ;
  67.     quantum = DEFQUANTUM;
  68. #ifdef i386
  69.     affinity = 0;
  70. #endif /* i386 */
  71. #ifdef PROFILE
  72.     numprofilers = 1;
  73.     QInit();
  74. #endif
  75. }
  76.  
  77.  
  78. void
  79. Main::run ()
  80. {
  81.     Thread *t, *mainthread;
  82.  
  83.     mainthread = new Thread("_MAIN_", 0, 0);    // run on same stack
  84.     mainthread->setflags(TF_SCHEDULER|TF_KEEPSTACK|TF_NONPREEMPTABLE);
  85.  
  86.     //
  87.     // "thisthread" refers to the current thread of execution running
  88.     // right here, right now.  Make our thread point at the static process
  89.     // object until we have our own process object to reference into.
  90.     //
  91.     mainthread->setproc(sysproc);
  92.     thisthread = mainthread;
  93.  
  94.     prestoState = MAIN_INIT;
  95.     // give the programmer a chance
  96.     if (main_exit_code = Main::init())    {    // non-zero return
  97.         return;                    // is bad news
  98.     }
  99.  
  100. #ifdef PROFILE
  101.     if ((numprocessors + numprofilers) > NUMPROCS)
  102.         {
  103.         cout << "Too many processors: " << numprocessors 
  104.                     << numprofilers << "\n";
  105.         return;                    // is bad news
  106.         }
  107.     QBegin(numprocessors, numprofilers, affinity);
  108. #endif
  109.  
  110. #ifdef sun
  111.     numprocessors = 1;
  112. #endif /* sun */
  113. #if defined(vax)
  114.     // VAX unix version runs on uniprocessors only for now.
  115.     numprocessors = 1;
  116. #endif /* vax */
  117. #ifdef mips
  118.     numprocessors = 1;
  119. #endif /* mips */
  120.  
  121.     if (thisthread != mainthread)
  122.         thisthread = mainthread;
  123.     prestoState = MAIN_MAIN;
  124.  
  125.     //
  126.     // prime the scheduler
  127.     //
  128. #ifdef DEBUG_STARTUP
  129.         cout << "invoking ctor for scheduler\n";
  130.     cout.flush();
  131. #endif /* DEBUG_STARTUP */
  132.     if (sched == (Scheduler*)0)
  133.         sched = new Scheduler(numprocessors,quantum);  // sets thisproc
  134.  
  135.     //
  136.     // t becomes the first schedulable thread
  137.     // Since we only have one processor, and no preemption here
  138.     // we return with t on the ready q.
  139.     //
  140. #ifdef DEBUG_STARTUP
  141.         cout << "making thread SCHEDULER_STARTER\n";
  142.     cout.flush();
  143. #endif /* DEBUG_STARTUP */
  144.     t = mainthread->newthread ("SCHEDULER_STARTER");
  145.     t->nonpreemptable();
  146.     t->start(0, (PFany) start_Scheduler, sched);
  147.  
  148.     //
  149.     // Build the main threads and readyq them
  150.     //
  151. #ifdef DEBUG_STARTUP
  152.         cout << "making the main threads\n";
  153.     cout.flush();
  154. #endif /* DEBUG_STARTUP */
  155.     for (int i = 0; i < nummainthreads; i++)    {);    char buf[8];        // lotsa threads
  156.         sprintf(buf,"%s.%d", MAINNAME, i);
  157.         char *name = new char[strlen(buf)+1];
  158.         strcpy(name, buf);
  159.         Thread *t = mainthread->newthread (name, i+1, mainstacksizes);
  160.         t->start(0, (PFany) start_Main, this);
  161.     }
  162.  
  163.     // Crank up the scheduler in the context of thisthread.
  164.     //    This will read the SCHEDULER thread off the
  165.     //    the readyq, invoke that thread
  166.     //    on the scheduler itself, which will cause the scheduler
  167.     //    to then create numprocessors copies of itself (each
  168.     //    running on its own stack).  The SCHEDULER thread
  169.     //    is guaranteed not to block and will be the first thread
  170.     //    to terminate, so we can quickly reuse it.
  171.     //    
  172.  
  173.     //
  174.     // Bind this thread to a processor which will start up all the
  175.     // coschedulers.  Thisthread will not be queued since it's a scheduler.
  176.     // We have to start it up directly.
  177.     //
  178. #ifdef DEBUG_STARTUP
  179.         cout << "about to start scheduler\n"; cout.flush ();
  180.         cout.flush();
  181. #endif /* DEBUG_STARTUP */
  182.  
  183.     mainthread->isrunning();
  184.     thisproc->invoke();            // start thisproc which will start 
  185.                     // the scheduler thread which will
  186.                     // start all the processor threads
  187.                     // which will then pull the main
  188.                     // threads off the readyq
  189.     mainthread->isnotrunning();
  190.  
  191.     //
  192.     // Since shutdown is not synchronized, there is a race condition which
  193.     // can result in sched getting deleted while process objects are still
  194.     // active.  If it hurts, don't do it.
  195.     //
  196.     //    if (sched)
  197.     //        delete sched;
  198.     //
  199.  
  200.     delete thisproc;
  201.     thisproc = sysproc;
  202.  
  203.     //delete thisthread;         /* done in runrun */
  204.     //thisthread = 0;
  205.     //
  206.     // Threads are out... thisthread is undefined at this point
  207.     //
  208.     // should be single unix process by now
  209.  
  210.     cout << "HALT" << endl << flush;
  211.     prestoState = MAIN_DONE;
  212.     main_exit_code = Main::done();
  213. }
  214.  
  215.  
  216. Main::~Main()
  217. {
  218. }
  219.  
  220.  
  221. //
  222. // Preallocate tons of threads in the parent process's address space.
  223. // This is a temporary hack to get around the brain-damaged sequent
  224. // shared memory implementation.
  225. //
  226. // NOTE: not called from anywhere in Presto.
  227. //
  228. int
  229. Main::preallocthreads(int cnt, int sz)
  230. {
  231.     int j;
  232.  
  233.     j = cnt;
  234.     Thread **tlist = new Thread*[j];
  235.     while (j--)    {    
  236.         tlist[j] = thisthread->newthread ("any",    
  237.                     0,    // any id
  238.                     sz);    // stack size
  239.     }
  240.     j = cnt;
  241.     while (j--)    {
  242.         delete tlist[j];
  243.     }
  244.     delete tlist;
  245.     return cnt;
  246. }
  247.  
  248. typedef void    (*PF)();
  249. extern PF set_new_handler(PF);
  250. extern void failed_malloc();
  251.  
  252. void
  253. main(int argc, char **argv, char **envp)
  254. {
  255.     set_new_handler(failed_malloc);
  256.  
  257.     //
  258.     // Create a new main thread.
  259.     //
  260.  
  261.     MAIN = new Main(argc, argv, envp);
  262.         MAIN->run ();
  263.  
  264.     if (MAIN)
  265.         delete MAIN;
  266.  
  267.     prestoState = STATIC_DTOR;
  268.     
  269.     while (wait(0) != -1)        // collect kids, get execution stats
  270.         continue;
  271.  
  272. #ifdef __DECCXX
  273.     /* cxx has a wierd effect that shows up during the
  274.        static destructor calls that occur during an exit().
  275.        calling _exit() avoids this, but the problem
  276.        needs resolving.
  277.      */
  278.  
  279.     _exit(main_exit_code);
  280. #else
  281.     exit (main_exit_code);
  282. #endif /* __DECCXX */
  283. }    
  284.